#pragma once
#ifndef OBR_PERSPECTIVECAMERA_H
#define OBR_PERSPECTIVECAMERA_H

#include "common.h"
#include "core/Camera.h"

namespace OBR
{
class PerspectiveCamera : public Camera, public Configurable<PerspectiveCamera>
{
    /*data*/
public:
    float3 orig, lookat, up;
    float width, height, znear, zfar, fov,
        aspect_ratio; // width & height can be obtained using fov & aspect-ratio
private:
    bool should_calc_width_height;
    float3 U, V, W; // used to generate ray direction
    float3 cam_front, cam_up, cam_right;

    /*methods*/
public:
    PerspectiveCamera();
    PerspectiveCamera(float3 orig, float3 lookat, float3 up, float znear, float zfar,
                      float width = -1, float height = -1, float fov = -1, float aspect_ratio = -1);
    ~PerspectiveCamera();

private:
    void calculateParams();

public:
    /* --------------------------- override Camera -------------------------- */

    void rotate(float2 deg) override;
    void translate(float2 dir) override;
    void zoom(float dist) override;

    /* ------------------------ override ProgramEntry ----------------------- */

    /**
     * @brief upload data to sbt payload
     *
     */
    void uploadSbtData() override;

protected:
    /* ------------------------ override Configurable ----------------------- */

    /**
     * @brief create object from config
     *
     * @param config
     */
    void _buildFromConfig(const Json::Value &config) override;

private:
    /* ------------------------ override ProgramEntry ----------------------- */

    /**
     * @brief Get the Program Group Options of this type
     *
     * @return OptixProgramGroupOptions&
     */
    OptixProgramGroupOptions &getProgramGroupOptions() override;

    /**
     * @brief Get the Program Group Desc of this type
     *
     * @return OptixProgramGroupOptions&
     */
    OptixProgramGroupDesc &getProgramGroupDesc() override;
};

} // namespace OBR

#endif